#ifndef SOURCETRACERAY_TRACE_HPP
#define SOURCETRACERAY_TRACE_HPP
#include "Math.hpp"
using byte = unsigned char;

class CGameTrace;
using trace_t = CGameTrace;

#define   DISPSURF_FLAG_SURFACE           (1<<0)
#define   DISPSURF_FLAG_WALKABLE          (1<<1)
#define   DISPSURF_FLAG_BUILDABLE         (1<<2)
#define   DISPSURF_FLAG_SURFPROP1         (1<<3)
#define   DISPSURF_FLAG_SURFPROP2         (1<<4)

// 平面
struct cplane_t
{
    Vector	normal;
    float	dist{};
    byte	type{};			// for fast side tests
    [[maybe_unused]] byte	signbits{};		// signx + (signy<<1) + (signz<<1)
    byte	pad[2]{};
};

// 表面
struct csurface_t
{
    const char* name;
    short		    surfaceProps;
    unsigned short	flags;		// BUG: These are declared per surface, not per material, but this database is per-material now
};

// Trace基类
class CBaseTrace
{
public:
    // 位移标志测试
    [[maybe_unused]] [[nodiscard]] bool IsDispSurface() const { return ((dispFlags & DISPSURF_FLAG_SURFACE) != 0); }
    [[maybe_unused]] [[nodiscard]] bool IsDispSurfaceWalkable() const { return ((dispFlags & DISPSURF_FLAG_WALKABLE) != 0); }
    [[maybe_unused]] [[nodiscard]] bool IsDispSurfaceBuildable() const { return ((dispFlags & DISPSURF_FLAG_BUILDABLE) != 0); }
    [[maybe_unused]] [[nodiscard]] bool IsDispSurfaceProp1() const { return ((dispFlags & DISPSURF_FLAG_SURFPROP1) != 0); }
    [[maybe_unused]] [[nodiscard]] bool IsDispSurfaceProp2() const { return ((dispFlags & DISPSURF_FLAG_SURFPROP2) != 0); }

public:

    // these members are aligned!!
    Vector			startpos;				// 起始点
    Vector			endpos;					// 结束点
    cplane_t		plane;					// 撞击时的表面法线

    float			fraction;				// 完成时间, 1.0 = 没有击中任何东西

    int				contents;				// 表面另一侧的内容物击中
    unsigned short	dispFlags;				// 用于用数据标记表面的位移标志

    bool			allsolid;				// 如果为真，则平面无效
    bool			startsolid;				// 如果为真，则初始点位于实心区域

    CBaseTrace();

private:
    // No copy constructors allowed
    CBaseTrace(const CBaseTrace& vOther);
};

CBaseTrace::CBaseTrace() {

}

class CGameTrace : public CBaseTrace
{
public:
    bool DidHitWorld() const;
    bool DidHitNonWorldEntity() const;
    int GetEntityIndex() const;
    bool DidHit() const;
    bool IsVisible() const;

public:

    float		fractionleftsolid;		// time we left a solid, only valid if we started in solid
    csurface_t	surface;				// surface hit (impact surface)
    int			hitgroup;				// 0 == generic, non-zero is specific body part
    short		physicsbone;			// physics bone hit by trace in studio
    unsigned short      worldSurfaceIndex;  // Index of the msurface2_t, if applicable
    //CBaseEntity* m_pEnt;
    void* m_pEnt;
    int			hitbox;					// box hit by trace in studio

    CGameTrace() {}

private:
    // No copy constructors allowed
    CGameTrace(const CGameTrace& vOther);
};

#endif //SOURCETRACERAY_TRACE_HPP
